import {
    _RouteRecordBase,
    NavigationFailure,
    RouteLocationNormalized,
    RouteLocationRaw,
    RouteRecordMultipleViews,
    RouteRecordMultipleViewsWithChildren,
    RouteRecordRedirect,
    RouteRecordSingleView,
    RouteRecordSingleViewWithChildren,
    RouterOptions,
} from "vue-router";
import {ComponentPublicInstance} from "vue";

// ############### vue router ####################
type VueRouterOptions =
    | Omit<RouterOptions, "routes">
    | {
  routes: AppRoutes<any>;
};

const defaultVueRouterOptions: Pick<RouterOptions, "scrollBehavior"> = {
  scrollBehavior(to, from, savedPosition): any {
    if (savedPosition) {
      return savedPosition;
    }
    const result: any = {
      left: 0,
      top: 0,
      behavior: "smooth",
    };

    if (to.hash) {
      result.el = to.hash;
    }
    return result;
  },
};

// ############### 自定义路由 ####################
enum RouteListMode {
  /**
   - 跳转路由如果是excludeList中的路由将被阻挡
   - 跳转路由如果是非excludeList中的路由是否被阻挡取决于 nonListRoutePermit 值
   */
  ALLOW = "allow",
  /**
   - 跳转路由如果是excludeList中的路由将被放行
   - 跳转路由如果是非excludeList中的路由是否被阻挡取决于 nonListRoutePermit 值
   */
  BLOCK = "block",
}

type NonInExcludeListRoutePermitType =
    | boolean
    | ((to: RouteLocationNormalized, from: RouteLocationNormalized) => boolean)
    | ((
    to: RouteLocationNormalized,
    from: RouteLocationNormalized
) => Promise<boolean>);

type NavigationGuardReturn =
    | void
    | Error
    | RouteLocationRaw
    | boolean
    | ((vm: ComponentPublicInstance) => unknown);

type BeforeEachReturnType =
    | NavigationGuardReturn
    | Promise<NavigationGuardReturn>;

// 自定义路由配置
interface CustomRouterOptions {
  // 是否显示loading。默认值false
  showLoading?: boolean | (() => boolean);
  // 显示loading的函数。默认无动作
  showLoadingFunction?: () => void;
  // 隐藏loading的函数。默认无动作
  hideLoadingFunction?: (routeSuccess: boolean) => void;
  // 显示loading后的钩子函数。默认无动作
  afterShowLoading?: (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized
  ) => void;

  // route模式。默认值block
  routeListMode?: RouteListMode;
  // 排除路由名单。默认值为空数组
  excludeList?:
      | string[]
      | ((
      to: RouteLocationNormalized,
      from: RouteLocationNormalized
  ) => string[]);
  // excludeList路由放行行为，返回值作为vue router的全局前置守卫返回值。默认返回值为 true
  excludeListRoutePermitFunction?: (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized
  ) => BeforeEachReturnType;
  // excludeList路由不放行的行为，返回值作为vue router的全局前置守卫返回值。默认返回值为 false
  excludeListRouteForbidFunction?: (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized
  ) => BeforeEachReturnType;

  // 非名单路由是否放行。默认为false
  nonInExcludeListRoutePermit?: NonInExcludeListRoutePermitType;
  // 其它路由放行的行为，返回值作为vue router的全局前置守卫返回值。默认返回值为 true
  nonInExcludeRoutePermitFunction?: (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized
  ) => BeforeEachReturnType;
  // 其它路由不放行的行为，返回值作为vue router的全局前置守卫返回值。默认返回值为 false
  nonInExcludeRouteForbidFunction?: (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized
  ) => BeforeEachReturnType;

  // 路由后的钩子函数。默认无动作
  afterEach?: (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized,
      failure?: NavigationFailure | void
  ) => void;
}

// 自定义路由默认配置对象
const defaultCustomRouterOptions: Required<CustomRouterOptions> = {
  showLoading: false,
  showLoadingFunction() {},
  hideLoadingFunction() {},
  afterShowLoading() {},

  routeListMode: RouteListMode.BLOCK,
  excludeList: [],
  excludeListRoutePermitFunction() { return true; },
  excludeListRouteForbidFunction() { return false; },

  nonInExcludeListRoutePermit: false,
  nonInExcludeRoutePermitFunction() { return true; },
  nonInExcludeRouteForbidFunction() { return false; },
  afterEach() {},
};

// ############# AppRoute API #################
interface AppRouteWithLayout<META> {
  layout?: AppRoute<META> | ((appRoutes: AppRoutes<META>) => AppRoute<META>);
}

// 重写VueRouter相关类型
interface AppRouteRecordBase<META>
    extends Omit<_RouteRecordBase, "meta" | "props" | "redirect" | "children"> {
  meta?: META;
}

interface AppRouteRecordSingleViewWithLayout<META>
    extends Omit<RouteRecordSingleView, "children" | "meta">,
        AppRouteRecordBase<META>,
        AppRouteWithLayout<META> {}

interface AppRouteRecordSingleViewWithoutChildrenWithLayout<META>
    extends Omit<RouteRecordSingleViewWithChildren, "children" | "meta">,
        AppRouteRecordBase<META>,
        AppRouteWithLayout<META> {}

interface AppRouteRecordMultipleViewsWithLayout<META>
    extends Omit<RouteRecordMultipleViews, "children" | "meta">,
        AppRouteRecordBase<META>,
        AppRouteWithLayout<META> {}

interface AppRouteRecordMultipleViewsWithoutChildrenWithLayout<META>
    extends Omit<RouteRecordMultipleViewsWithChildren, "children" | "meta">,
        AppRouteRecordBase<META>,
        AppRouteWithLayout<META> {}

interface AppRouteRecordRedirect<META>
    extends Omit<RouteRecordRedirect, "children" | "meta">,
        AppRouteRecordBase<META> {}

// AppRoute、AppRoutes
type AppRoute<META> =
    | AppRouteRecordSingleViewWithLayout<META>
    | AppRouteRecordSingleViewWithoutChildrenWithLayout<META>
    | AppRouteRecordMultipleViewsWithLayout<META>
    | AppRouteRecordMultipleViewsWithoutChildrenWithLayout<META>
    | AppRouteRecordRedirect<META>;

type AppRoutes<META> = {
  [propName: string]: AppRoute<META>;
};

export {
  RouteListMode,
  AppRoute,
  AppRoutes,
  CustomRouterOptions,
  defaultCustomRouterOptions,
  BeforeEachReturnType,
  VueRouterOptions,
  defaultVueRouterOptions
}
